package com.yonyougov.devops.cruxcisupport.util;

import com.jcraft.jsch.*;
import com.yonyougov.devops.cruxcisupport.server.ServerEntity;
import io.micrometer.core.instrument.util.IOUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.springframework.core.io.ClassPathResource;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;

@Slf4j
public class SshUtil {

    public String exeCmd(ServerEntity serverEntity, String cmd) {
        return exeCmd(serverEntity, cmd, null);
    }

    public String exeCmd(ServerEntity serverEntity, String cmd, Integer timeout) {
        Session session = null;
        try {
            session = createSession(serverEntity);
            String result = exeCmd(session, cmd, timeout);
            session.disconnect();
            return result;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        } finally {
            if (session != null) {
                session.disconnect();
            }
        }
    }

    private String exeCmd(Session session, String cmd, Integer timeout) throws Exception {
        log.debug("准备执行命令:{}", cmd);
        ChannelExec channel = (ChannelExec) session.openChannel("exec");
        channel.setCommand(cmd);

        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        channel.setErrStream(bos);
        InputStream in = channel.getInputStream();


        channel.connect(timeout == null ? 0 :timeout);
        String result = IOUtils.toString(in, StandardCharsets.UTF_8).trim();

        log.debug("命令:{}执行完成", cmd);
        channel.disconnect();
        log.debug("断开channel");

        log.debug("命令执行结果:{}", result);

        if (channel.getExitStatus() != 0) {
            String errorInfo = bos.toString("UTF-8");
            log.error("命令:{}执行错误信息:{}", cmd, errorInfo);
        }
        bos.close();
        return result;
    }

    private void exeCmdNoReturn(Session session, String cmd) throws Exception {
        log.debug("准备执行命令:{}", cmd);
        ChannelExec channel = (ChannelExec) session.openChannel("exec");
        channel.setCommand(cmd);
        channel.connect();
        log.debug("命令:{}执行完成", cmd);
        channel.disconnect();
        log.debug("断开channel");
    }

    public void exeCmdNoReturn(ServerEntity serverEntity, String cmd) {
        Session session = null;
        try {
            session = createSession(serverEntity);
            exeCmdNoReturn(session, cmd);
            session.disconnect();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (session != null) {
                session.disconnect();
            }
        }
    }

    private Session createSession(ServerEntity serverEntity) throws Exception {
        JSch jsch = new JSch();
        Session session;
        if (serverEntity.getConnectType() == 2) {
            session = jsch.getSession(serverEntity.getUsername(), serverEntity.getIp(), serverEntity.getPort());
            session.setPassword(serverEntity.getPassword());
        } else {
            jsch.setKnownHosts(new ClassPathResource(".ssh/known_hosts").getInputStream());
            File tempFile = File.createTempFile("id_rsa", "");
            try (InputStream inputStream = new ClassPathResource(".ssh/id_rsa").getInputStream()) {
                FileUtils.copyInputStreamToFile(inputStream, tempFile);
                jsch.addIdentity(tempFile.getPath());
            } catch (Exception e) {
                e.printStackTrace();
            }
            session = jsch.getSession(serverEntity.getUsername(), serverEntity.getIp(), serverEntity.getPort());
            session.setConfig("PreferredAuthentications", "publickey");
            session.setConfig("StrictHostKeyChecking", "no");
            if (tempFile.exists()) {
                tempFile.delete();
            }
        }

        UserInfo userInfo = new UserInfo() {
            @Override
            public String getPassphrase() {
                System.out.println("getPassphrase");
                return null;
            }

            @Override
            public String getPassword() {
                System.out.println("getPassword");
                return null;
            }

            @Override
            public boolean promptPassword(String s) {
                System.out.println("promptPassword:" + s);
                return false;
            }

            @Override
            public boolean promptPassphrase(String s) {
                System.out.println("promptPassphrase:" + s);
                return false;
            }

            @Override
            public boolean promptYesNo(String s) {
                System.out.println("promptYesNo:" + s);
                return true;//notice here!
            }

            @Override
            public void showMessage(String s) {
                System.out.println("showMessage:" + s);
            }
        };

        session.setUserInfo(userInfo);
        session.connect();
        return session;
    }

    public boolean check(ServerEntity serverEntity,Integer timeout) {
        try {
            JSch jsch = new JSch();
            Session session;
            if (serverEntity.getConnectType() == 2) {
                session = jsch.getSession(serverEntity.getUsername(), serverEntity.getIp(), serverEntity.getPort());
                session.setPassword(serverEntity.getPassword());
            } else {
                jsch.setKnownHosts(new ClassPathResource(".ssh/known_hosts").getInputStream());
                File tempFile = File.createTempFile("id_rsa", "");
                try (InputStream inputStream = new ClassPathResource(".ssh/id_rsa").getInputStream()) {
                    FileUtils.copyInputStreamToFile(inputStream, tempFile);
                    jsch.addIdentity(tempFile.getPath());
                } catch (Exception e) {
                    e.printStackTrace();
                }
                session = jsch.getSession(serverEntity.getUsername(), serverEntity.getIp(), serverEntity.getPort());
                session.setConfig("PreferredAuthentications", "publickey");
                session.setConfig("StrictHostKeyChecking", "no");
                if (tempFile.exists()) {
                    tempFile.delete();
                }
            }

            UserInfo userInfo = new UserInfo() {
                @Override
                public String getPassphrase() {
                    System.out.println("getPassphrase");
                    return null;
                }

                @Override
                public String getPassword() {
                    System.out.println("getPassword");
                    return null;
                }

                @Override
                public boolean promptPassword(String s) {
                    System.out.println("promptPassword:" + s);
                    return false;
                }

                @Override
                public boolean promptPassphrase(String s) {
                    System.out.println("promptPassphrase:" + s);
                    return false;
                }

                @Override
                public boolean promptYesNo(String s) {
                    System.out.println("promptYesNo:" + s);
                    return true;//notice here!
                }

                @Override
                public void showMessage(String s) {
                    System.out.println("showMessage:" + s);
                }
            };

            session.setUserInfo(userInfo);
            session.connect(timeout);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("捕获异常");
            return false;
        }

    }

    public void operateFile(ServerEntity serverEntity) {
        Session session = null;
        ChannelSftp channel = null;
        try {
            session = createSession(serverEntity);
            channel = (ChannelSftp) session.openChannel("sftp");
            channel.connect(10000000);
            File file = new File("D:\\Download\\sshd_config");
            channel.put(new FileInputStream(file), "/root/.ssh/sshd_config", ChannelSftp.OVERWRITE);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (session != null) {
                session.disconnect();
            }
            if (channel != null) {
                channel.disconnect();
            }
        }

    }
}
